/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

#include <Carbon/Carbon.h>
#include <Quicktime/Quicktime.h>//YV

#include <unistd.h>
#include <cstdio>
#include <cmath>

//#define MS_TO_TICKS(a) a*3/50

#define LABELWIDTH 64
#define INTERWIDGETSPACE 16
#define WIDGETHEIGHT 32
#define NO_KEY -1

struct CvWindow;

typedef struct CvTrackbar {
	int signature;

	ControlRef trackbar;
	ControlRef label;

	char* name;
	CvTrackbar* next;
	CvWindow* parent;
	int* data;
	int pos;
	int maxval;
	int labelSize;//Yannick Verdie
	CvTrackbarCallback notify;
	CvTrackbarCallback2 notify2;
	void* userdata;
}
CvTrackbar;


typedef struct CvWindow {
	int signature;

	char* name;
	CvWindow* prev;
	CvWindow* next;

	WindowRef window;
	WindowRef oldwindow;//YV
	CGImageRef imageRef;
	int imageWidth;//FD
	int imageHeight;//FD

	CvMat* image;
	CvMat* dst_image;
	int converted;
	int last_key;
	int flags;
	int status;//YV
	Ptr restoreState;//YV

	CvMouseCallback on_mouse;
	void* on_mouse_param;

	struct {
		int pos;
		int rows;
		CvTrackbar* first;
	}
	toolbar;
	int trackbarheight;
}
CvWindow;

static CvWindow* hg_windows = 0;

#define Assert(exp)                                             \
if( !(exp) )                                                    \
{                                                               \
    printf("Assertion: %s  %s: %d\n", #exp, __FILE__, __LINE__);\
    assert(exp);                                                \
}

static int wasInitialized = 0;
static char lastKey = NO_KEY;
OSStatus keyHandler(EventHandlerCallRef hcr, EventRef theEvent, void* inUserData);
static pascal OSStatus windowEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* inUserData);

static const EventTypeSpec applicationKeyboardEvents[] = {
	{ kEventClassKeyboard, kEventRawKeyDown },
};

CV_IMPL int cvInitSystem( int argc, char** argv ) {
	OSErr err = noErr;
	if ( !wasInitialized ) {

		hg_windows = 0;
		err = InstallApplicationEventHandler(NewEventHandlerUPP( keyHandler), GetEventTypeCount(applicationKeyboardEvents), applicationKeyboardEvents, NULL, NULL);
		if (err != noErr) {
			fprintf(stderr, "InstallApplicationEventHandler was not ok\n");
		}
		wasInitialized = 1;
	}

	return 0;
}

// TODO: implement missing functionality
CV_IMPL int cvStartWindowThread() {
	return 0;
}

static int icvCountTrackbarInWindow( const CvWindow* window) {
	CvTrackbar* trackbar = window->toolbar.first;
	int count = 0;
	while (trackbar != 0) {
		count++;
		trackbar = trackbar->next;
	}
	return count;
}

static CvTrackbar* icvTrackbarByHandle( void* handle ) {
	CvWindow* window = hg_windows;
	CvTrackbar* trackbar = NULL;
	while ( window != 0 && window->window != handle) {
		trackbar = window->toolbar.first;
		while (trackbar != 0 && trackbar->trackbar != handle) {
			trackbar = trackbar->next;
		}
		if (trackbar != 0 && trackbar->trackbar == handle) {
			break;
		}
		window = window->next;
	}
	return trackbar;
}

static CvWindow* icvWindowByHandle( void* handle ) {
	CvWindow* window = hg_windows;

	while ( window != 0 && window->window != handle) {
		window = window->next;
	}

	return window;
}

CV_IMPL CvWindow* icvFindWindowByName( const char* name) {
	CvWindow* window = hg_windows;
	while ( window != 0 && strcmp(name, window->name) != 0 ) {
		window = window->next;
	}

	return window;
}

static CvTrackbar* icvFindTrackbarByName( const CvWindow* window, const char* name ) {
	CvTrackbar* trackbar = window->toolbar.first;

	while (trackbar != 0 && strcmp( trackbar->name, name ) != 0) {
		trackbar = trackbar->next;
	}

	return trackbar;
}

//FD
/* draw image to frame */
static void icvDrawImage( CvWindow* window ) {
	Assert( window != 0 );
	if ( window->imageRef == 0 ) { return; }

	CGContextRef myContext;
	CGRect rect;
	Rect portrect;
	int width = window->imageWidth;
	int height = window->imageHeight;

	GetWindowPortBounds(window->window, &portrect);

	if (!( window->flags & CV_WINDOW_AUTOSIZE) ) { //YV
		CGPoint origin = {0, 0};
		CGSize size = {portrect.right - portrect.left, portrect.bottom - portrect.top - window->trackbarheight};
		rect.origin = origin; rect.size = size;
	} else {
		CGPoint origin = {0, portrect.bottom - height - window->trackbarheight};
		CGSize size = {width, height};
		rect.origin = origin; rect.size = size;
	}

	/* To be sybnchronous we are using this, better would be to susbcribe to the draw event and process whenever requested, we might save SOME CPU cycles*/
	SetPortWindowPort (window->window);
	QDBeginCGContext (GetWindowPort (window->window), &myContext);
	CGContextSetInterpolationQuality (myContext, kCGInterpolationLow);
	CGContextDrawImage(myContext, rect, window->imageRef);
	CGContextFlush(myContext);// 4
	QDEndCGContext (GetWindowPort(window->window), &myContext);// 5
}

//FD
/* update imageRef */
static void icvPutImage( CvWindow* window ) {
	Assert( window != 0 );
	if ( window->image == 0 ) { return; }

	CGColorSpaceRef colorspace = NULL;
	CGDataProviderRef provider = NULL;
	int width = window->imageWidth = window->image->cols;
	int height = window->imageHeight = window->image->rows;

	colorspace = CGColorSpaceCreateDeviceRGB();

	int size = 8;
	int nbChannels = 3;

	provider = CGDataProviderCreateWithData(NULL, window->image->data.ptr, width * height , NULL );

	if (window->imageRef != NULL) {
		CGImageRelease(window->imageRef);
		window->imageRef = NULL;
	}

	window->imageRef = CGImageCreate( width, height, size , size * nbChannels , window->image->step, colorspace,  kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault );
	icvDrawImage( window );

	/* release the provider's memory */
	CGDataProviderRelease( provider );
}

static void icvUpdateWindowSize( const CvWindow* window ) {
	int width = 0, height = 240; /* init à al taille de base de l'image*/
	Rect globalBounds;

	GetWindowBounds(window->window, kWindowContentRgn, &globalBounds);

	int minWidth = 320;

	if ( window->image ) {
		width = MAX(MAX(window->image->width, width), minWidth);
		height = window->image->height;
	} else {
		width = minWidth;
	}

	height += window->trackbarheight;

	//height +=WIDGETHEIGHT; /* 32 pixels are spearating tracbars from the video display */

	globalBounds.right = globalBounds.left + width;
	globalBounds.bottom = globalBounds.top + height;
	SetWindowBounds(window->window, kWindowContentRgn, &globalBounds);
}

static void icvDeleteWindow( CvWindow* window ) {
	CvTrackbar* trackbar;

	if ( window->prev ) {
		window->prev->next = window->next;
	} else {
		hg_windows = window->next;
	}

	if ( window->next ) {
		window->next->prev = window->prev;
	}

	window->prev = window->next = 0;

	cvReleaseMat( &window->image );
	cvReleaseMat( &window->dst_image );

	for ( trackbar = window->toolbar.first; trackbar != 0; ) {
		CvTrackbar* next = trackbar->next;
		cvFree( (void**)&trackbar );
		trackbar = next;
	}

	if (window->imageRef != NULL) {
		CGImageRelease(window->imageRef);
	}

	DisposeWindow (window->window);//YV

	cvFree( (void**)&window );
}


CV_IMPL void cvDestroyWindow( const char* name) {
	CV_FUNCNAME( "cvDestroyWindow" );

	__BEGIN__;

	CvWindow* window;

	if (!name) {
		CV_ERROR( CV_StsNullPtr, "NULL name string" );
	}

	window = icvFindWindowByName( name );
	if ( !window ) {
		EXIT;
	}

	icvDeleteWindow( window );

	__END__;
}


CV_IMPL void cvDestroyAllWindows( void ) {
	while ( hg_windows ) {
		CvWindow* window = hg_windows;
		icvDeleteWindow( window );
	}
}


CV_IMPL void cvShowImage( const char* name, const CvArr* arr) {
	CV_FUNCNAME( "cvShowImage" );

	__BEGIN__;

	CvWindow* window;
	int origin = 0;
	int resize = 0;
	CvMat stub, *image;

	if ( !name ) {
		CV_ERROR( CV_StsNullPtr, "NULL name" );
	}

	window = icvFindWindowByName(name);
	if (!window) {
		cvNamedWindow(name, 1);
		window = icvFindWindowByName(name);
	}

	if ( !window || !arr ) {
		EXIT;    // keep silence here.
	}

	if ( CV_IS_IMAGE_HDR( arr )) {
		origin = ((IplImage*)arr)->origin;
	}

	CV_CALL( image = cvGetMat( arr, &stub ));

	/*
	 if( !window->image )
	 cvResizeWindow( name, image->cols, image->rows );
	 */

	if ( window->image &&
			!CV_ARE_SIZES_EQ(window->image, image) ) {
		if ( ! (window->flags & CV_WINDOW_AUTOSIZE) ) { //FD
			resize = 1;
		}
		cvReleaseMat( &window->image );
	}

	if ( !window->image ) {
		resize = 1;//FD
		window->image = cvCreateMat( image->rows, image->cols, CV_8UC3 );
	}

	cvConvertImage( image, window->image, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB );
	icvPutImage( window );
	if ( resize ) { //FD
		icvUpdateWindowSize( window );
	}

	__END__;
}

CV_IMPL void cvResizeWindow( const char* name, int width, int height) {
	CV_FUNCNAME( "cvResizeWindow" );

	__BEGIN__;

	CvWindow* window;
	//CvTrackbar* trackbar;

	if ( !name ) {
		CV_ERROR( CV_StsNullPtr, "NULL name" );
	}

	window = icvFindWindowByName(name);
	if (!window) {
		EXIT;
	}

	SizeWindow(window->window, width, height, true);

	__END__;
}

CV_IMPL void cvMoveWindow( const char* name, int x, int y) {
	CV_FUNCNAME( "cvMoveWindow" );

	__BEGIN__;

	CvWindow* window;
	//CvTrackbar* trackbar;

	if ( !name ) {
		CV_ERROR( CV_StsNullPtr, "NULL name" );
	}

	window = icvFindWindowByName(name);
	if (!window) {
		EXIT;
	}

	MoveWindow(window->window, x, y, true);

	__END__;
}

void TrackbarActionProcPtr (ControlRef theControl, ControlPartCode partCode) {
	CvTrackbar* trackbar = icvTrackbarByHandle (theControl);

	if (trackbar == NULL) {
		fprintf(stderr, "Error getting trackbar\n");
		return;
	} else {
		int pos = GetControl32BitValue (theControl);
		if ( trackbar->data ) {
			*trackbar->data = pos;
		}
		if ( trackbar->notify ) {
			trackbar->notify(pos);
		} else if ( trackbar->notify2 ) {
			trackbar->notify2(pos, trackbar->userdata);
		}

		//--------YV---------------------------
		CFStringEncoding encoding = kCFStringEncodingASCII;
		CFAllocatorRef alloc_default = kCFAllocatorDefault;  // = NULL;

		char valueinchar[20];
		sprintf(valueinchar, " (%d)",  *trackbar->data);

		// create an empty CFMutableString
		CFIndex maxLength = 256;
		CFMutableStringRef cfstring = CFStringCreateMutable(alloc_default, maxLength);

		// append some c strings into it.
		CFStringAppendCString(cfstring, trackbar->name, encoding);
		CFStringAppendCString(cfstring, valueinchar, encoding);

		SetControlData(trackbar->label, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(cfstring), &cfstring);
		DrawControls(trackbar->parent->window);
		//-----------------------------------------
	}
}


static int icvCreateTrackbar (const char* trackbar_name,
							  const char* window_name,
							  int* val, int count,
							  CvTrackbarCallback on_notify,
							  CvTrackbarCallback2 on_notify2,
							  void* userdata) {
	int result = 0;

	CV_FUNCNAME( "icvCreateTrackbar" );
	__BEGIN__;

	/*char slider_name[32];*/
	CvWindow* window = 0;
	CvTrackbar* trackbar = 0;
	Rect  stboundsRect;
	ControlRef outControl;
	ControlRef stoutControl;
	Rect bounds;

	if ( !window_name || !trackbar_name ) {
		CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
	}

	if ( count <= 0 ) {
		CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
	}

	window = icvFindWindowByName(window_name);
	if ( !window ) {
		EXIT;
	}

	trackbar = icvFindTrackbarByName(window, trackbar_name);
	if ( !trackbar ) {
		int len = strlen(trackbar_name);
		trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1);
		memset( trackbar, 0, sizeof(*trackbar));
		trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
		trackbar->name = (char*)(trackbar + 1);
		memcpy( trackbar->name, trackbar_name, len + 1 );
		trackbar->parent = window;
		trackbar->next = window->toolbar.first;
		window->toolbar.first = trackbar;

		if ( val ) {
			int value = *val;
			if ( value < 0 ) {
				value = 0;
			}
			if ( value > count ) {
				value = count;
			}
			trackbar->pos = value;
			trackbar->data = val;
		}

		trackbar->maxval = count;

		//----------- YV ----------------------
		//get nb of digits
		int nbDigit = 0;
		while ((count /= 10) > 10) {
			nbDigit++;
		}

		//pad size maxvalue in pixel
		Point	qdSize;
		char valueinchar[strlen(trackbar_name)+1 +1 +1+nbDigit+1];//lenght+\n +space +(+nbDigit+)
		sprintf(valueinchar, "%s (%d)", trackbar_name, trackbar->maxval);
		SInt16	baseline;
		CFStringRef text = CFStringCreateWithCString(NULL, valueinchar, kCFStringEncodingASCII);
		GetThemeTextDimensions( text, kThemeCurrentPortFont, kThemeStateActive, false, &qdSize, &baseline );
		trackbar->labelSize = qdSize.h;
		//--------------------------------------

		int c = icvCountTrackbarInWindow(window);

		GetWindowBounds(window->window, kWindowContentRgn, &bounds);

		stboundsRect.top = (INTERWIDGETSPACE + WIDGETHEIGHT) * (c - 1) + INTERWIDGETSPACE;
		stboundsRect.left = INTERWIDGETSPACE;
		stboundsRect.bottom = stboundsRect.top + WIDGETHEIGHT;
		stboundsRect.right = stboundsRect.left + LABELWIDTH;

		//fprintf(stdout,"create trackabar bounds (%d %d %d %d)\n",stboundsRect.top,stboundsRect.left,stboundsRect.bottom,stboundsRect.right);
		//----------- YV ----------------------
		sprintf(valueinchar, "%s (%d)", trackbar_name, trackbar->pos);
		CreateStaticTextControl (window->window, &stboundsRect, CFStringCreateWithCString(NULL, valueinchar, kCFStringEncodingASCII), NULL, &stoutControl);
		//--------------------------------------

		stboundsRect.top = (INTERWIDGETSPACE + WIDGETHEIGHT) * (c - 1) + INTERWIDGETSPACE;
		stboundsRect.left = INTERWIDGETSPACE * 2 + LABELWIDTH;
		stboundsRect.bottom = stboundsRect.top + WIDGETHEIGHT;
		stboundsRect.right =  bounds.right - INTERWIDGETSPACE;

		CreateSliderControl (window->window, &stboundsRect, trackbar->pos, 0, trackbar->maxval, kControlSliderLiveFeedback, 0, true, NewControlActionUPP(TrackbarActionProcPtr), &outControl);

		bounds.bottom += INTERWIDGETSPACE + WIDGETHEIGHT;
		SetControlVisibility (outControl, true, true);
		SetControlVisibility (stoutControl, true, true);

		trackbar->trackbar = outControl;
		trackbar->label = stoutControl;
		if (c == 1) {
			window->trackbarheight = INTERWIDGETSPACE * 2 + WIDGETHEIGHT;
		} else {
			window->trackbarheight += INTERWIDGETSPACE + WIDGETHEIGHT;
		}
		icvUpdateWindowSize( window );
	}

	trackbar->notify = on_notify;
	trackbar->notify2 = on_notify2;
	trackbar->userdata = userdata;

	result = 1;

	__END__;
	return result;
}


CV_IMPL int cvCreateTrackbar (const char* trackbar_name,
							  const char* window_name,
							  int* val, int count,
							  CvTrackbarCallback on_notify) {
	return icvCreateTrackbar(trackbar_name, window_name, val, count, on_notify, 0, 0);
}


CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,
							  const char* window_name,
							  int* val, int count,
							  CvTrackbarCallback2 on_notify2,
							  void* userdata) {
	return icvCreateTrackbar(trackbar_name, window_name, val,
							 count, 0, on_notify2, userdata);
}


CV_IMPL void
cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) {
	CvWindow* window = icvFindWindowByName( name );
	if (window != NULL) {
		window->on_mouse = function;
		window->on_mouse_param = info;
	} else {
		fprintf(stdout, "Error with cvSetMouseCallback. Window not found : %s\n", name);
	}
}

CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) {
	int pos = -1;

	CV_FUNCNAME( "cvGetTrackbarPos" );

	__BEGIN__;

	CvWindow* window;
	CvTrackbar* trackbar = 0;

	if ( trackbar_name == 0 || window_name == 0 ) {
		CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
	}

	window = icvFindWindowByName( window_name );
	if ( window ) {
		trackbar = icvFindTrackbarByName( window, trackbar_name );
	}

	if ( trackbar ) {
		pos = trackbar->pos;
	}

	__END__;

	return pos;
}

CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) {
	CV_FUNCNAME( "cvSetTrackbarPos" );

	__BEGIN__;

	CvWindow* window;
	CvTrackbar* trackbar = 0;

	if ( trackbar_name == 0 || window_name == 0 ) {
		CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
	}

	window = icvFindWindowByName( window_name );
	if ( window ) {
		trackbar = icvFindTrackbarByName( window, trackbar_name );
	}

	if ( trackbar ) {
		if ( pos < 0 ) {
			pos = 0;
		}

		if ( pos > trackbar->maxval ) {
			pos = trackbar->maxval;
		}

		// Set new value and redraw the trackbar
		SetControlValue( trackbar->trackbar, pos );
		Draw1Control( trackbar->trackbar );
	}

	__END__;
	return ;
}

CV_IMPL void* cvGetWindowHandle( const char* name ) {
	WindowRef result = 0;

	__BEGIN__;

	CvWindow* window;
	window = icvFindWindowByName( name );
	if (window != NULL) {
		result = window->window;
	} else {
		result = NULL;
	}

	__END__;

	return result;
}


CV_IMPL const char* cvGetWindowName( void* window_handle ) {
	const char* window_name = "";

	CV_FUNCNAME( "cvGetWindowName" );

	__BEGIN__;

	CvWindow* window;

	if ( window_handle == 0 ) {
		CV_ERROR( CV_StsNullPtr, "NULL window" );
	}
	window = icvWindowByHandle(window_handle );
	if ( window ) {
		window_name = window->name;
	}

	__END__;

	return window_name;
}

double cvGetMode_QT(const char* name) { //YV
	double result = -1;

	CV_FUNCNAME( "cvGetMode_QT" );

	__BEGIN__;

	CvWindow* window;

	if (!name) {
		CV_ERROR( CV_StsNullPtr, "NULL name string" );
	}

	window = icvFindWindowByName( name );
	if ( !window ) {
		CV_ERROR( CV_StsNullPtr, "NULL window" );
	}

	result = window->status;

	__END__;
	return result;
}

void cvChangeMode_QT( const char* name, double prop_value) { //Yannick Verdie
	OSStatus err = noErr;


	CV_FUNCNAME( "cvChangeMode_QT" );

	__BEGIN__;

	CvWindow* window;

	if (!name) {
		CV_ERROR( CV_StsNullPtr, "NULL name string" );
	}

	window = icvFindWindowByName( name );
	if ( !window ) {
		CV_ERROR( CV_StsNullPtr, "NULL window" );
	}

	if (window->flags & CV_WINDOW_AUTOSIZE) { //if the flag CV_WINDOW_AUTOSIZE is set
		EXIT;
	}

	if (window->status == CV_WINDOW_FULLSCREEN && prop_value == CV_WINDOW_NORMAL) {
		err = EndFullScreen(window->restoreState, 0);
		if (err != noErr) {
			fprintf(stdout, "Error EndFullScreen\n");
		}
		window->window = window->oldwindow;
		ShowWindow( window->window );

		window->status = CV_WINDOW_NORMAL;
		EXIT;
	}

	if (window->status == CV_WINDOW_NORMAL && prop_value == CV_WINDOW_FULLSCREEN) {
		GDHandle device;
		err = GetWindowGreatestAreaDevice(window->window, kWindowTitleBarRgn, &device, NULL);
		if (err != noErr) {
			fprintf(stdout, "Error GetWindowGreatestAreaDevice\n");
		}

		HideWindow(window->window);
		window->oldwindow = window->window;
		err = BeginFullScreen(&(window->restoreState), device, 0, 0, &window->window, 0, fullScreenAllowEvents | fullScreenDontSwitchMonitorResolution);
		if (err != noErr) {
			fprintf(stdout, "Error BeginFullScreen\n");
		}

		window->status = CV_WINDOW_FULLSCREEN;
		EXIT;
	}

	__END__;
}

CV_IMPL int cvNamedWindow( const char* name, int flags ) {
	int result = 0;
	CV_FUNCNAME( "cvNamedWindow" );
	if (!wasInitialized) {
		cvInitSystem(0, NULL);
	}

	// to be able to display a window, we need to be a 'faceful' application
	// http://lists.apple.com/archives/carbon-dev/2005/Jun/msg01414.html
	static bool switched_to_faceful = false;
	if (! switched_to_faceful) {
		ProcessSerialNumber psn = { 0, kCurrentProcess };
		OSStatus ret = TransformProcessType (&psn, kProcessTransformToForegroundApplication );

		if (ret == noErr) {
			SetFrontProcess( &psn );
			switched_to_faceful = true;
		} else {
			fprintf(stderr, "Failed to tranform process type: %d\n", (int) ret);
			fflush (stderr);
		}
	}

	__BEGIN__;

	WindowRef       outWindow = NULL;
	OSStatus              err = noErr;
	Rect        contentBounds = {100, 100, 320, 440};

	CvWindow* window;
	UInt wAttributes = 0;

	int len;

	const EventTypeSpec genericWindowEventHandler[] = {
		{ kEventClassMouse, kEventMouseMoved},
		{ kEventClassMouse, kEventMouseDragged},
		{ kEventClassMouse, kEventMouseUp},
		{ kEventClassMouse, kEventMouseDown},
		{ kEventClassWindow, kEventWindowClose },
		{ kEventClassWindow, kEventWindowBoundsChanged }//FD
	};

	if ( !name ) {
		CV_ERROR( CV_StsNullPtr, "NULL name string" );
	}

	if ( icvFindWindowByName( name ) != 0 ) {
		result = 1;
		EXIT;
	}
	len = strlen(name);
	CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
	memset( window, 0, sizeof(*window));
	window->name = (char*)(window + 1);
	memcpy( window->name, name, len + 1 );
	window->flags = flags;
	window->status = CV_WINDOW_NORMAL;//YV
	window->signature = CV_WINDOW_MAGIC_VAL;
	window->image = 0;
	window->last_key = 0;
	window->on_mouse = 0;
	window->on_mouse_param = 0;

	window->next = hg_windows;
	window->prev = 0;
	if ( hg_windows ) {
		hg_windows->prev = window;
	}
	hg_windows = window;
	wAttributes =  kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute;


	if (window->flags & CV_WINDOW_AUTOSIZE) { //Yannick verdie, remove the handler at the bottom-right position of the window in AUTORESIZE mode
		wAttributes = 0;
		wAttributes = kWindowCloseBoxAttribute | kWindowFullZoomAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute  |  kWindowLiveResizeAttribute;
	}

	err = CreateNewWindow ( kDocumentWindowClass, wAttributes, &contentBounds, &outWindow);
	if (err != noErr) {
		fprintf(stderr, "Error while creating the window\n");
	}

	SetWindowTitleWithCFString(outWindow, CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII));
	if (err != noErr) {
		fprintf(stdout, "Error SetWindowTitleWithCFString\n");
	}

	window->window = outWindow;
	window->oldwindow = 0;//YV

	err = InstallWindowEventHandler(outWindow, NewEventHandlerUPP(windowEventHandler), GetEventTypeCount(genericWindowEventHandler), genericWindowEventHandler, outWindow, NULL);

	ShowWindow( outWindow );
	result = 1;

	__END__;
	return result;
}

static pascal OSStatus windowEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* inUserData) {
	CvWindow* window = NULL;
	UInt32 eventKind, eventClass;
	OSErr err = noErr;
	int event = 0;
	UInt32 count = 0;
	HIPoint point = {0, 0};
	EventMouseButton eventMouseButton = 0;//FD
	UInt32 modifiers;//FD

	WindowRef theWindow = (WindowRef)inUserData;
	if (theWindow == NULL) {
		return eventNotHandledErr;
	}
	window = icvWindowByHandle(theWindow);
	if ( window == NULL) {
		return eventNotHandledErr;
	}

	eventKind = GetEventKind(theEvent);
	eventClass = GetEventClass(theEvent);

	switch (eventClass) {
	case kEventClassMouse : {
		switch (eventKind) {
		case kEventMouseUp :
		case kEventMouseDown :
		case kEventMouseMoved :
		case kEventMouseDragged : {
			err = CallNextEventHandler(nextHandler, theEvent);
			if (err != eventNotHandledErr) {
				return err;
			}
			err = GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(eventMouseButton), NULL, &eventMouseButton);
			err = GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers);
			err = GetEventParameter(theEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, &count);
			if (err == noErr) {
				if (count > 1) { event += 6; }
			} else {
				event = CV_EVENT_MOUSEMOVE;
			}

			if (eventKind == kEventMouseUp) {
				event += 4;
			}
			if (eventKind == kEventMouseDown) {
				event += 1;
			}

			unsigned int flags = 0;

			err = GetEventParameter(theEvent, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof(point), NULL, &point);
			if (eventKind != kEventMouseMoved) {
				switch (eventMouseButton) {
				case kEventMouseButtonPrimary:
					if (modifiers & controlKey) {
						flags += CV_EVENT_FLAG_RBUTTON;
						event += 1;
					} else {
						flags += CV_EVENT_FLAG_LBUTTON;
					}
					break;
				case kEventMouseButtonSecondary:
					flags += CV_EVENT_FLAG_RBUTTON;
					event += 1;
					break;
				case kEventMouseButtonTertiary:
					flags += CV_EVENT_FLAG_MBUTTON;
					event += 2;
					break;
				}
			}

			if (modifiers & controlKey) { flags += CV_EVENT_FLAG_CTRLKEY; }
			if (modifiers & shiftKey) { flags += CV_EVENT_FLAG_SHIFTKEY; }
			if (modifiers & cmdKey ) { flags += CV_EVENT_FLAG_ALTKEY; }

			if (window->on_mouse != NULL) {
				int lx, ly;
				Rect structure, content;
				GetWindowBounds(theWindow, kWindowStructureRgn, &structure);
				GetWindowBounds(theWindow, kWindowContentRgn, &content);
				lx = (int)point.x - content.left + structure.left;
				ly = (int)point.y - window->trackbarheight  - content.top + structure.top; /* minus la taille des trackbars */
				if (window->flags & CV_WINDOW_AUTOSIZE) {//FD
					//printf("was %d,%d\n", lx, ly);
					/* scale the mouse coordinates */
					lx = lx * window->imageWidth / (content.right - content.left);
					ly = ly * window->imageHeight / (content.bottom - content.top - window->trackbarheight);
				}

				if (lx > 0 && ly > 0) { /* a remettre dans les coordonnées locale */
					window->on_mouse (event, lx, ly, flags, window->on_mouse_param);
					return noErr;
				}
			}
		}
		default : return eventNotHandledErr;
		}
	}
	case kEventClassWindow : {//FD
		switch (eventKind) {
		case kEventWindowBoundsChanged : {
			/* resize the trackbars */
			CvTrackbar* t;
			Rect bounds;
			GetWindowBounds(window->window, kWindowContentRgn, &bounds);
			for ( t = window->toolbar.first; t != 0; t = t->next ) {
				SizeControl(t->trackbar, bounds.right - bounds.left - INTERWIDGETSPACE * 3 - LABELWIDTH , WIDGETHEIGHT);
			}
		}
		/* redraw the image */
		icvDrawImage(window);
		break;
		default :
			return eventNotHandledErr;
		}
	}
	default:
		return eventNotHandledErr;
	}

	return eventNotHandledErr;
}

OSStatus keyHandler(EventHandlerCallRef hcr, EventRef theEvent, void* inUserData) {
	UInt32 eventKind;
	UInt32 eventClass;
	OSErr  err        = noErr;

	eventKind  = GetEventKind     (theEvent);
	eventClass = GetEventClass    (theEvent);
	err        = GetEventParameter(theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(lastKey), NULL, &lastKey);
	if (err != noErr) {
		lastKey = NO_KEY;
	}

	return noErr;
}

CV_IMPL int cvWaitKey (int maxWait) {
	EventRecord theEvent;

	// wait at least for one event (to allow mouse, etc. processing), exit if maxWait milliseconds passed (nullEvent)
	UInt32 start = TickCount();
	int iters = 0;
	do {
		// remaining time until maxWait is over
		UInt32 wait = EventTimeToTicks (maxWait / 1000.0) - (TickCount() - start);
		if ((int)wait <= 0) {
			if ( maxWait > 0 && iters > 0 ) {
				break;
			}
			wait = 1;
		}
		iters++;
		WaitNextEvent (everyEvent, &theEvent, maxWait > 0 ? wait : kDurationForever, NULL);
	} while (lastKey == NO_KEY  &&  theEvent.what != nullEvent);

	int key = lastKey;
	lastKey = NO_KEY;
	return key;
}

/* End of file. */
